import { Controller } from 'egg'
import { ParameterRules } from 'parameter'
import { UserProps } from '../model/user'

export const userErr = {
  inputValidateErr: {
    errno: 101001,
    msg: '输入内容不合法',
  },
  createUserRepeatErr: {
    errno: 101002,
    msg: '当前用户已存在',
  },
  loginErr: {
    errno: 101003,
    msg: '用户名或密码错误',
  },
  userAuthenticationErr: {
    errno: 101004,
    msg: '用户认证失败',
  },
  sendVeriCodeFrequentlyErr: {
    errno: 101005,
    msg: '请勿频繁发送验证码',
  },
  makeVeriCodeErr: {
    errno: 101005,
    msg: '验证码生成异常，请重试',
  },
  wrongVeriCodeErr: {
    errno: 101005,
    msg: '短信验证码错误',
  },
  oauthLoginErr: {
    errno: 101006,
    msg: '第三方授权登录异常，请重试',
  },
}

const userRule: ParameterRules<Partial<UserProps>> = {
  username: 'email',
  password: { type: 'password', min: 8 },
}

const veriCodeRule: ParameterRules<{ phoneNumber }> = {
  phoneNumber: { type: 'string', format: /^(?:(?:\+|00)86)?1\d{10}$/, message: '手机号码格式错误' },
}
const phoneLoginRule: ParameterRules<{ phoneNumber: string; code: string }> = {
  phoneNumber: { type: 'string', format: /^(?:(?:\+|00)86)?1\d{10}$/, message: '手机号码格式错误' },
  code: { type: 'string', format: /^\d{1,}$/, message: '验证码格式错误' },
}

export default class UserController extends Controller {
  private validateInput(rule: ParameterRules) {
    const { ctx, app } = this
    const errs = app.validator.validate(rule, ctx.request.body)
    return errs
  }

  /**
   * 注册用户
   */
  public async createUserByEmail() {
    const { ctx, service } = this
    const errs = this.validateInput(userRule)
    if (errs) {
      return ctx.helper.error({ errType: 'inputValidateErr', error: errs })
    }
    const isUserExist = await service.user.getUserByName(ctx.request.body.username)
    if (isUserExist) {
      return ctx.helper.error({ errType: 'createUserRepeatErr' })
    }
    const { username, password } = ctx.request.body
    const userInfo: Partial<UserProps> = {
      username,
      password,
      email: username,
    }
    const resUserData = await service.user.createUser(userInfo)
    return ctx.helper.success({ resp: resUserData.toJSON() })
  }

  /**
   * 通过邮箱密码登录
   */
  async loginByEmail() {
    const { ctx, service } = this
    const errs = this.validateInput(userRule)
    if (errs) {
      return ctx.helper.error({ errType: 'inputValidateErr', error: errs })
    }
    const user = await service.user.getUserByName(ctx.request.body.username)
    if (!user) {
      return ctx.helper.error({ errType: 'loginErr' })
    }
    const isRightPassword = await ctx.compare(ctx.request.body.password, user.password!)
    if (!isRightPassword) {
      return ctx.helper.error({ errType: 'loginErr' })
    }
    const token = ctx.helper.jwtUsername(user.username)
    return ctx.helper.success({ resp: { token }, msg: '登录成功' })
  }

  /**
   * 通过手机验证码登录
   */
  public async loginByCellphone() {
    const { ctx, service, app } = this
    const errs = this.validateInput(phoneLoginRule)
    if (errs) {
      return ctx.helper.error({ errType: 'inputValidateErr', error: errs })
    }
    const { phoneNumber, code } = ctx.request.body
    const key = `vericode-${phoneNumber}`
    const oldVeriCode = await app.redis.get(key)
    if (code !== oldVeriCode) {
      return ctx.helper.error({ errType: 'wrongVeriCodeErr' })
    }
    const token = await service.user.loginByCellphone(phoneNumber)
    return ctx.helper.success({ resp: { token }, msg: '登录成功' })
  }

  /**
   * 获取用户信息
   */
  public async getUserInfo() {
    const { ctx, service } = this
    const resUserData = await service.user.getUserByName(ctx.state.user.username)
    if (resUserData) {
      return ctx.helper.success({ resp: resUserData })
    }
    return ctx.helper.error({ errType: 'userAuthenticationErr' })
  }

  /**
   * 发送手机验证码
   */
  public async sendVeriCode() {
    const { ctx, app } = this
    const errs = this.validateInput(veriCodeRule)
    if (errs) {
      return ctx.helper.error({ errType: 'inputValidateErr', error: errs })
    }
    // key vericode-13778828312
    const key = `vericode-${ctx.request.body.phoneNumber}`
    // 检查redis中是否存在已生成验证码
    const oldVeriCode = await app.redis.get(key)
    if (oldVeriCode) {
      return ctx.helper.error({ errType: 'sendVeriCodeFrequentlyErr' })
    }

    // 生成四位随机数，并存入redis 60s
    const newVeriCode = Math.floor(Math.random() * 9000 + 1000).toString()
    const saveNewVeriCodeRes = await app.redis.set(key, newVeriCode, 'ex', 60)
    if (saveNewVeriCodeRes !== 'OK') {
      return ctx.helper.error({ errType: 'makeVeriCodeErr' })
    }
    if (app.config.env === 'local') {
      return ctx.helper.success({ resp: { code: newVeriCode } })
    }
    return ctx.helper.success({ msg: '验证码发送成功' })
  }

  public async oauthToGitee() {
    const { ctx, app } = this
    const { client_id, redictUrl } = app.config.giteeOAuthConfig
    ctx.redirect(
      `https://gitee.com/oauth/authorize?client_id=${client_id}&redirect_uri=${redictUrl}&response_type=code`,
    )
  }

  public async oauthByGitee() {
    const { ctx, service } = this
    const { code } = ctx.request.query
    try {
      const token = await service.user.loginByGiteeOAuth(code)
      ctx.helper.success({ resp: { token }, msg: '登录成功' })
    } catch (error) {
      ctx.helper.error({ errType: 'oauthLoginErr', error })
    }
  }
}
